#pragma once
namespace graph
{
   inline void vertex_iterator_t::operator ++ ()
   {
      ++it_;
   }
   inline vertex_t const & vertex_iterator_t::operator * () const
   {
      return *it_;
   }
   inline vertex_t& vertex_iterator_t::operator * ()
   {
      return *it_;
   }
   inline bool vertex_iterator_t::operator != (vertex_iterator_t const & right) const
   {
      return it_ != right.it_;
   }
   inline bool vertex_iterator_t::operator == (vertex_iterator_t const & right) const
   {
      return !(*this != right);
   }
   
   inline void edge_iterator_t::operator ++ ()
   {
      if(it_ != it_end_) 
      {
        ++it_;
        if (it_ == it_end_) 
            ++(*this);
      }
      else
      {
        ++cur_v_it_;
        if (cur_v_it_ != end_v_it_)
        {            
            it_ = graph_->get_vertex_edges((*cur_v_it_).get_id()).first;
            it_end_ = graph_->get_vertex_edges((*cur_v_it_).get_id()).second;
            if (it_ == it_end_) 
               ++(*this);
        }
      }
   }
   inline edge_t const edge_iterator_t::operator * () const
   {
      return edge_t(it_, (*cur_v_it_).get_id());
   }
   inline edge_t edge_iterator_t::operator * ()
   {
      return edge_t(it_, (*cur_v_it_).get_id());
   }
   inline bool edge_iterator_t::operator != (edge_iterator_t const & right) const
   {
      return it_ != right.it_;
   }
   inline bool edge_iterator_t::operator == (edge_iterator_t const & right) const
   {
      return !(*this != right);
   }
   template<>
   inline adj_vertices_iterator_t<forward_adj>::adj_vertices_iterator_t(vertex_id_t id, graph_t& g)
      :  it_(g.get_vertex_edges(id).first)
      ,  g_(&g)
      ,  source_v_id_(id)
   {}
   template<>
   inline adj_vertices_iterator_t<reverse_adj>::adj_vertices_iterator_t(vertex_id_t id, graph_t& g)
      :  it_(g.get_vertex_in_edges(id).first)
      ,  g_(&g)
      ,  source_v_id_(id)
   {}
   template<adj_iterator_mode_e mode>
   inline void adj_vertices_iterator_t<mode>::operator ++ ()
   {
      ++it_;
   }
   template<adj_iterator_mode_e mode>
   inline vertex_t const & adj_vertices_iterator_t<mode>::operator * () const
   {
      return (*g_)[it_->get_target_vertex_id()];
   }
   template<adj_iterator_mode_e mode>
   inline vertex_t& adj_vertices_iterator_t<mode>::operator * ()
   {
      return (*g_)[it_->get_target_vertex_id()];
   }
   template<adj_iterator_mode_e mode>
   inline edge_t const adj_vertices_iterator_t<mode>::edge() const
   {
      return edge_t(it_, source_v_id_);
   }
   template<adj_iterator_mode_e mode>
   inline edge_t adj_vertices_iterator_t<mode>::edge()
   {
      return edge_t(it_, source_v_id_);
   }
   template<adj_iterator_mode_e mode>
   inline vertex_id_t adj_vertices_iterator_t<mode>::source_id() const
   {
      return source_v_id_;
   }
   template<adj_iterator_mode_e mode>      
   inline bool adj_vertices_iterator_t<mode>::operator != (adj_vertices_iterator_t<mode> const& right) const
   {
      return it_ != right.it_;
   }
   template<adj_iterator_mode_e mode>
   inline bool adj_vertices_iterator_t<mode>::operator == (adj_vertices_iterator_t<mode> const& right) const
   {
      return !(*this != right);
   }    
   template<>
   inline adj_vertices_iterator_pair_t<forward_adj>::type 
      adj_vertices_iterator_t<forward_adj>::adj_vertices(vertex_id_t source_v_id, graph_t& g)
   {
      //if (mode == forward_adj)
         return adj_vertices_iterator_pair_t<forward_adj>::type(
                     adj_vertices_iterator_t<forward_adj>(source_v_id, g), 
                     adj_vertices_iterator_t<forward_adj>(g.get_vertex_edges(source_v_id).second)
                     );
      /*else 
         return typename adj_vertices_iterator_pair_t<reverse_adj>::type(
                        adj_vertices_iterator_t<reverse_adj>(source_v_id, g), 
                        adj_vertices_iterator_t<reverse_adj>(g.get_vertex_in_edges(source_v_id).second)
                        );*/
   }
   template<>
   inline adj_vertices_iterator_pair_t<reverse_adj>::type 
      adj_vertices_iterator_t<reverse_adj>::adj_vertices(vertex_id_t source_v_id, graph_t& g)
   {
      /*if (mode == forward_adj)
         return typename adj_vertices_iterator_pair_t<forward_adj>::type(
                        adj_vertices_iterator_t<forward_adj>(source_v_id, g), 
                        adj_vertices_iterator_t<forward_adj>(g.get_vertex_edges(source_v_id).second)
                        );
      else */
         return adj_vertices_iterator_pair_t<reverse_adj>::type(
                        adj_vertices_iterator_t<reverse_adj>(source_v_id, g),
                        adj_vertices_iterator_t<reverse_adj>(g.get_vertex_in_edges(source_v_id).second)
                        );
   }
   
   template<>   
   inline adj_edges_iterator_t<forward_adj>::adj_edges_iterator_t(vertex_id_t source_v_id, graph_t& g)
      :  source_v_id_(source_v_id)
      ,  it_(g.get_vertex_edges(source_v_id).first)
   {}
   
   template<>   
   inline adj_edges_iterator_t<reverse_adj>::adj_edges_iterator_t(vertex_id_t source_v_id, graph_t& g)
      :  source_v_id_(source_v_id)
      ,  it_(g.get_vertex_in_edges(source_v_id).first)
   {}
   template<adj_iterator_mode_e mode>   
   inline void adj_edges_iterator_t<mode>::operator ++ ()
   {
      ++it_;
   }
   template<adj_iterator_mode_e mode>
   inline edge_t const adj_edges_iterator_t<mode>::operator * () const
   {
      return edge_t(it_, source_v_id_);
   }
   template<adj_iterator_mode_e mode>
   inline edge_t adj_edges_iterator_t<mode>::operator * ()
   {
      return edge_t(it_, source_v_id_);
   }
   template<adj_iterator_mode_e mode>
   inline bool adj_edges_iterator_t<mode>::operator != (adj_edges_iterator_t<mode> const & right) const
   {
      return it_ != right.it_;
   }   
   template<adj_iterator_mode_e mode>
   inline bool adj_edges_iterator_t<mode>::operator == (adj_edges_iterator_t<mode> const & right) const
   {
      return !(*this != right);
   }   
   template<adj_iterator_mode_e mode>
   inline vertex_id_t adj_edges_iterator_t<mode>::source_id() const
   {
      return source_v_id_;
   }
   template<>
   inline adj_edges_iterator_pair_t<forward_adj>::type 
      adj_edges_iterator_t<forward_adj>::adj_edges(vertex_id_t source_v_id, graph_t& g)
   {
         return adj_edges_iterator_pair_t<forward_adj>::type(
                        adj_edges_iterator_t<forward_adj>(source_v_id, g), 
                        adj_edges_iterator_t<forward_adj>(g.get_vertex_edges(source_v_id).second)
                     );
   }      
   
   template<>
   inline adj_edges_iterator_pair_t<reverse_adj>::type 
      adj_edges_iterator_t<reverse_adj>::adj_edges(vertex_id_t source_v_id, graph_t& g)
   {
      return adj_edges_iterator_pair_t<reverse_adj>::type(
               adj_edges_iterator_t<reverse_adj>(source_v_id, g), 
               adj_edges_iterator_t<reverse_adj>(g.get_vertex_in_edges(source_v_id).second)
         );
   }
   
   inline vertex_iterator_pair_t vertices(graph_t& g)
   {
      return vertex_iterator_pair_t(vertex_iterator_t(g), vertex_iterator_t( &g[0] + g.get_vertex_count() ));
   }
   inline edge_iterator_pair_t edges(graph_t& g)
   {
      return edge_iterator_pair_t(edge_iterator_t(g), edge_iterator_t( g.get_vertex_edges(0).first + g.get_edge_count() ));
   }
   template<adj_iterator_mode_e mode>
   inline typename adj_edges_iterator_pair_t<mode>::type adj_edges(vertex_id_t source_v_id, graph_t& g)
   {
      return adj_edges_iterator_t<mode>::adj_edges(source_v_id, g);
   }

   template<adj_iterator_mode_e mode>
   inline typename adj_vertices_iterator_pair_t<mode>::type adj_vertices(vertex_id_t source_v_id, graph_t& g)
   {
      return adj_vertices_iterator_t<mode>::adj_vertices(source_v_id, g);     
   }

}
